use std::borrow::BorrowMut;
use std::cell::RefCell;
use std::collections::HashMap;
use std::iter::Map;
use std::ops::Deref;
use std::rc::Rc;
use crate::class_file::byte_data_reader::ByteDataReader;
use crate::class_file::cf_constant_info::CFConstantInfoEnum;
use crate::class_file::class_file::ClassFile;
use crate::class_file::cp_attribute_info::AttributeInfoEnum;
use crate::class_path::class_path::ClassPath;
use crate::class::vm_access_flags::{ACC_PUBLIC, is_native, is_static};
use crate::class::vm_class::{VMClass, VMClassField, VMClassMethod, VMClassMethodDescriptor};
use crate::class::vm_class_attr::{VMCLASS_ATTR_CODE_INVALID, VMClassAttrCode, VMClassAttrEnum};
use crate::class::vm_class_constant_info::{create_vmclass_constant_info, VMClassConstantInfoEnum};
use crate::class::vm_class_method_descriptor_parser::VMClassMethodDescriptorParser;

pub trait ClassLoader {
    fn load_class(&mut self, class_name: &String) -> Result<Rc<VMClass>, String>;
    fn load_class_file(&self, class_name: &String) -> Result<ClassFile, String>;
}

pub struct BootstrapClassLoader {
    pub class_path: RefCell<ClassPath>,
    pub vm_class_cache: HashMap<String, Rc<VMClass>>,
}

#[macro_export]
macro_rules! get_constant_info_from_class_file {
    ($cf:expr, $index:expr, $enumname:ident) => ({
        let constant_info_result = $cf.get_cfconstant_info_by_index($index);
        match constant_info_result {
            Ok(info) => {
                match info {
                    crate::class_file::cf_constant_info::CFConstantInfoEnum::$enumname(v) => {
                        Ok(v.clone())
                    }
                    _ => {
                        Err(String::from("类型不匹配"))
                    }
                }
            }
            Err(msg) => {
                Err(msg)
            }
        }
    })
}

impl ClassLoader for BootstrapClassLoader {
    fn load_class(&mut self, class_name: &String) -> Result<Rc<VMClass>, String> {
        let val = self.vm_class_cache.get(class_name);
        if val.is_some() {
            return Ok(val.unwrap().clone());
        }

        if class_name.starts_with("[") {
            let obj_class_result = self.load_class(&"java/lang/Object".to_string());
            if obj_class_result.is_err() {
                panic!("{},{},{}", file!(), line!(), obj_class_result.err().unwrap());
            }
            let obj_class = obj_class_result.unwrap();

            self.vm_class_cache.insert(String::from(class_name), Rc::new(VMClass {
                access_flag: ACC_PUBLIC,
                name: String::from(class_name),
                super_class: RefCell::new(Some(obj_class)),
                interfaces: RefCell::new(vec![]),
                fields: RefCell::new(vec![]),
                methods: RefCell::new(vec![]),
                instance_slot_count: RefCell::new(0),
                static_slot: RefCell::new(Default::default()),
                constant_pool: RefCell::new(vec![]),
                init_status: RefCell::new(false),
            }));
            return Ok(self.vm_class_cache.get(class_name).unwrap().clone());
        }

        let result = self.create_vm_class(class_name);
        if result.is_err() {
            return Err(result.err().unwrap());
        }
        let rval = result.unwrap();
        self.init_vm_class(rval.clone());
        return Ok(rval);
    }

    fn load_class_file(&self, class_name: &String) -> Result<ClassFile, String> {
        let class_data_result = self.class_path.borrow().read_class(class_name);
        return match class_data_result {
            Err(err) => {
                Err(err)
            }
            Ok(data) => {
                ClassFile::create(&mut ByteDataReader::new(data))
            }
        };
    }
}

impl BootstrapClassLoader {
    pub fn new(jdk_lib_path: &String, class_path: &String) -> Result<BootstrapClassLoader, String> {
        let class_path_result = ClassPath::new(jdk_lib_path, class_path);
        if class_path_result.is_err() {
            return Err(class_path_result.err().unwrap());
        }
        let mut class_loader = BootstrapClassLoader {
            class_path: RefCell::new(class_path_result.unwrap()),
            vm_class_cache: HashMap::new(),
        };
        class_loader.init();
        return Ok(class_loader);
    }

    fn init(&mut self) {
        let obj_class_result = self.load_class(&"java/lang/Object".to_string());
        if obj_class_result.is_err() {
            panic!("{},{},{}", file!(), line!(), obj_class_result.err().unwrap());
        }
        let obj_class = obj_class_result.unwrap();

        for cls_name in ["boolean", "byte", "short", "int", "long", "char", "float", "double"] {
            self.vm_class_cache.insert(String::from(cls_name), Rc::new(VMClass {
                access_flag: ACC_PUBLIC,
                name: String::from(cls_name),
                super_class: RefCell::new(Some(obj_class.clone())),
                interfaces: RefCell::new(vec![]),
                fields: RefCell::new(vec![]),
                methods: RefCell::new(vec![]),
                instance_slot_count: RefCell::new(0),
                static_slot: RefCell::new(HashMap::with_capacity(0)),
                constant_pool: RefCell::new(vec![]),
                init_status: RefCell::new(false),
            }));
        }
    }

    fn create_vm_class(&mut self, class_name: &String) -> Result<Rc<VMClass>, String> {
        println!("load class:{}", class_name);
        let load_class_file_result = self.load_class_file(class_name);
        if let Err(msg) = load_class_file_result {
            return Err(msg);
        }
        let cf = load_class_file_result.unwrap();

        // 获取 access_flags
        let access_flags = cf.access_flags;

        // 获取类名称
        let cf_class_result = get_constant_info_from_class_file!(cf, (cf.this_class as usize), CFConstantInfoClass);
        if let Err(message) = cf_class_result {
            return Err(message);
        }
        let cf_class = cf_class_result.unwrap();
        let cf_class_name_result = get_constant_info_from_class_file!(cf, (cf_class.cp_index as usize), CFConstantInfoUTF8);
        if let Err(msg) = cf_class_name_result {
            return Err(msg);
        }
        let name = cf_class_name_result.unwrap().string;

        // 加载父类
        let super_vmclass: RefCell<Option<Rc<VMClass>>> = RefCell::new(None);
        if name.as_str() != "java/lang/Object" {
            let cf_super_class_result = get_constant_info_from_class_file!(cf, (cf.super_class as usize), CFConstantInfoClass);
            if let Err(message) = cf_super_class_result {
                return Err(message);
            }
            let cf_super_class = cf_super_class_result.unwrap();
            let cf_super_class_name_result = get_constant_info_from_class_file!(cf, (cf_super_class.cp_index as usize), CFConstantInfoUTF8);
            if let Err(msg) = cf_super_class_name_result {
                return Err(msg);
            }
            let cf_super_class_name = cf_super_class_name_result.unwrap();

            let load_super_class_result = self.load_class(&cf_super_class_name.string);
            match load_super_class_result {
                Ok(vmclass) => {
                    super_vmclass.replace(Some(vmclass));
                }
                Err(msg) => {
                    return Err(msg);
                }
            }
        }

        // 加载接口
        let ro_interfaces = cf.interfaces.borrow();
        let interfaces: RefCell<Vec<Rc<VMClass>>> = RefCell::new(Vec::new());
        for index in 0..ro_interfaces.len() {
            let cp_index = *ro_interfaces.get(index).unwrap() as usize;
            let interface_class_result = get_constant_info_from_class_file!(cf, (cp_index), CFConstantInfoClass);
            if let Err(msg) = interface_class_result {
                return Err(msg);
            }
            let interface_name_result = get_constant_info_from_class_file!(
                cf, (interface_class_result.unwrap().cp_index as usize), CFConstantInfoUTF8);
            if let Err(msg) = interface_name_result {
                return Err(msg);
            }
            match interface_name_result {
                Ok(interface_name) => {
                    let interface_load_result = self.load_class(&interface_name.string);
                    match interface_load_result {
                        Ok(interface) => { interfaces.borrow_mut().push(interface); }
                        Err(msg) => { return Err(msg); }
                    }
                }
                Err(msg) => {
                    return Err(msg);
                }
            }
        }

        // 加载字段
        let ro_cf_fields = cf.fields.borrow();
        let vm_class_fields: RefCell<Vec<Rc<RefCell<VMClassField>>>> = RefCell::new(vec![]);
        for index in 0..ro_cf_fields.len() {
            let cf_field_info = ro_cf_fields.get(index).unwrap();

            let field_access_flags = cf_field_info.access_flags;
            let field_name_result = get_constant_info_from_class_file!(
                cf, (cf_field_info.name_index as usize), CFConstantInfoUTF8);
            if let Err(msg) = field_name_result {
                return Err(msg);
            }
            let field_name = field_name_result.unwrap().string;
            let field_descriptor_result = get_constant_info_from_class_file!(
                cf, (cf_field_info.descriptor_index as usize), CFConstantInfoUTF8);
            if let Err(msg) = field_descriptor_result {
                return Err(msg);
            }
            let field_descriptor = field_descriptor_result.unwrap().string;

            vm_class_fields.borrow_mut().push(Rc::new(RefCell::new(VMClassField {
                access_flags: field_access_flags,
                name: field_name,
                descriptor: field_descriptor,
                slot_id: -1,
            })));
        }


        // 加载方法
        let mut class_method_descriptor_parser = VMClassMethodDescriptorParser::new();
        let ro_cf_methods = cf.methods.borrow();
        let vm_class_methods: RefCell<Vec<Rc<VMClassMethod>>> = RefCell::new(vec![]);
        for index in 0..ro_cf_methods.len() {
            let cf_method_info = ro_cf_methods.get(index).unwrap();

            let method_access_flags = cf_method_info.access_flags;
            let method_name_result = get_constant_info_from_class_file!(
                cf, (cf_method_info.name_index as usize), CFConstantInfoUTF8);
            if let Err(msg) = method_name_result {
                return Err(msg);
            }
            let method_name = method_name_result.unwrap().string;
            let method_descriptor_result = get_constant_info_from_class_file!(
                cf, (cf_method_info.descriptor_index as usize), CFConstantInfoUTF8);
            if let Err(msg) = method_descriptor_result {
                return Err(msg);
            }
            let method_descriptor = method_descriptor_result.unwrap().string;

            let vm_method_descriptor = class_method_descriptor_parser.parse(&method_descriptor);
            let mut args_count = vm_method_descriptor.param_type_list.borrow().len();
            if !is_static(method_access_flags) {
                args_count += 1;
            }

            let method_attrs = RefCell::new(vec![]);
            let mut code_attr_index = 0;
            let ro_attrs = cf_method_info.attributes.borrow();
            for index in 0..ro_attrs.len() {
                let attribute_info_enum = ro_attrs.get(index).unwrap();
                match attribute_info_enum {
                    AttributeInfoEnum::AttributeInfoCode { val } => {
                        let code = VMClassAttrEnum::VMClassAttrCode {
                            val: Rc::new(VMClassAttrCode {
                                max_stack: val.max_stack,
                                max_locals: val.max_locals,
                                args_count: args_count as u16,
                                code: val.code.clone(),
                            })
                        };
                        code_attr_index = index;
                        method_attrs.borrow_mut().push(code);
                    }
                    _ => {
                        method_attrs.borrow_mut().push(VMClassAttrEnum::VMClassAttrCodeInvalid { val: Rc::new(VMCLASS_ATTR_CODE_INVALID) });
                    }
                };
            }
            if is_native(method_access_flags) {
                let start_char = vm_method_descriptor.return_type.chars().next().unwrap();
                let return_code: u8 = match start_char {
                    'V' => { 0xb1 }
                    '[' | 'L' => { 0xb0 }
                    'D' => { 0xaf }
                    'F' => { 0xae }
                    'J' => { 0xad }
                    'B' | 'S' | 'I' | 'Z' => { 0xac }
                    _ => {
                        panic!("异常返回值类型:{},{},{}", file!(), line!(), &vm_method_descriptor.return_type);
                    }
                };
                method_attrs.borrow_mut().push(VMClassAttrEnum::VMClassAttrCode {
                    val: Rc::new(VMClassAttrCode {
                        max_stack: 0,
                        max_locals: 0,
                        args_count: args_count as u16,
                        // 0xff 保留指令
                        // 0x00 表示调用native方法，后续可以扩展其他功能
                        // return_code
                        code: Rc::new(RefCell::new(vec![0xff, 0x00, return_code])),
                    })
                });
                code_attr_index = method_attrs.borrow().len() - 1;
            }

            vm_class_methods.borrow_mut().push(Rc::new(VMClassMethod {
                access_flags: method_access_flags,
                name: method_name,
                descriptor: Box::new(vm_method_descriptor),
                attributes: method_attrs,
                code_attr_index,
            }));
        }

        // 解析常量池
        let constant_pool: RefCell<Vec<Rc<VMClassConstantInfoEnum>>> = RefCell::new(Vec::new());
        for cf_constant_info in cf.cf_constant_pool.borrow().iter() {
            let constant_info = create_vmclass_constant_info(cf_constant_info, &cf);
            constant_pool.borrow_mut().push(Rc::new(constant_info));
        }

        let result_val = Rc::new(VMClass {
            access_flag: access_flags,
            name,
            super_class: super_vmclass,
            interfaces,
            fields: vm_class_fields,
            methods: vm_class_methods,
            instance_slot_count: RefCell::new(-1),
            static_slot: RefCell::new(HashMap::with_capacity(0)),
            constant_pool,
            init_status: RefCell::new(false),
        });

        self.vm_class_cache.insert(String::from(class_name), result_val.clone());

        return Ok(result_val.clone());
    }

    fn init_vm_class(&self, vm_class: Rc<VMClass>) {
        let fields = vm_class.fields.borrow();
        // 初始化静态字段slotId
        {
            let mut static_field_slot_id_index = 0;
            for field in fields.iter() {
                let mut rw_field = field.deref().borrow_mut();
                if is_static(rw_field.access_flags) {
                    rw_field.slot_id = static_field_slot_id_index;
                    static_field_slot_id_index += 1;
                }
            }
            vm_class.static_slot.replace(HashMap::with_capacity(static_field_slot_id_index as usize));
        }
        // 初始化普通字段slotId
        {
            let mut field_slot_id_index = 0;
            for field in fields.iter() {
                let mut rw_field = field.deref().borrow_mut();
                if !is_static(rw_field.access_flags) {
                    rw_field.slot_id = field_slot_id_index;
                    field_slot_id_index += 1;
                }
            }
            vm_class.instance_slot_count.replace(field_slot_id_index);
        }
    }
}